最近的rails專案裡,看到了這行:
@cart = @cart || Cart.from_hash(session[:cart9527])
剛開始真的看不懂這段到底在幹嘛,為了想釐清觀念就查了一下資料,結果越查越多....而且方向還越來越偏XD
至於為什麼要特別寫這篇呢?我們已經知道Ruby中的等於是指派(Assign)的意思,那不就跟x += 1 等同於 x = x + 1而已嗎?
x ||= y 不是 x = x || y
難道這就是傳說中的Ruby界的WTF moment嗎?
那 x ||= y到底是什麼?
x ||= y
#expansion應該長
x || x = y
If x is not initialized, false, nil or undefined, then evaluate y and set a to the result.
如果x尚未被初始化、false或nil及undefined,x 等於 y(換句話說:y會指派給x),其他情況下,x值不變。
所以:
@cart = @cart || Cart.from_hash(session[:cart9527])
#跟下面程式碼不相同
@cart ||= Cart.from_hash(session[:cart9527])
@cart現在是nil,第一圈會找Cart.from_hash(session[:cart9527])指派給@cart,第二圈因為@cart已經有值,故會將值指向自己。
再來看看幾個例子:
x = nil # 或 x = false
y = 10
puts x ||= y # => x原本是nil,印出 x = 10
x = 2
y = 10
puts x ||= y # => x原本是2,印出 x = 2
puts x || x = y # => 2
puts x = x || y # => 2
剛剛才說,”x ||= y 不是 x = x || y“,那上面例子的第6行怎麼還會印出2?
這個議題在約10年前討(爭)論(辯)的非常熱烈,可看下圖有人將所有的討論串做整理,最多有500多人在討論,有興趣的朋友可以點進去連結看看在吵些什麼XD
最噁心的討論就像這樣:
#sample1
a ||= b
#sample2
a || a = b
#sample3
a ? a : a = b
#sample4
if a then
a
else
a = b
end
#sample5
a = a || b
#sample6
a = a ? a : b
#sample7
if a then
a = a
else
a = b
end
a || a = b, a ? a : a = b, if a then a else a = b end, and if a then a = a else a = b end will throw an error if a is undefined, whereas a ||= b and a = a || b will not. Also, a || a = b, a ? a : a = b, if a then a else a = b end, a = a ? a : b, and if a then a = a else a = b end evaluate a twice when a is truthy, whereas a ||= b and a = a || b do not.
看得我頭都暈了...且已經超過我能理解的範圍
如果x尚未被初始化、false或nil及undefined,則 x 等於 y (換句話說:y會指派給x),其他情況下,x值不變。
參考資料:
Conditional Assignment Operator in Ruby
Please explain nuances of ||=
What does ||= (or-equals) mean in Ruby?
The definitive list of ||= (OR Equal) threads and pages
Difference between a = a || b and a ||= b
Assignments
A short-circuit (||=) edge case
超級經典面試題: Ruby的 a ||= b (or-equals)是什麼意思呢?
“The man who can drive himself further once the effort gets painful is the man who will win.”
— Roger Bannister, Runner
本文同步發佈於: https://louiswuyj.tw/